#include "utils.h"

#include "hardware/lcd.h"
#include "hardware/lcd_init.h"
#include <string.h>
#include "app/text.h"
#include "mid/printf.h"

uint8_t IsChinese(const char* str)
{
    size_t size = strlen(str);
    if (size < 2)
        return 0;

    uint8_t c1 = str[0];
    uint8_t c2 = str[1];
    if ((c1 >= 0xA1 && c1 <= 0xF7) && (c2 >= 0xA1 && c2 <= 0xFE))
        return 1;
    return 0;
}

uint8_t CharCount(const char* str)
{
    if (IsChinese(str))
    {
        return strlen(str) / 2;
    }
    return strlen(str);
}

int StrWidth(const char* str)
{
    size_t cnt = strlen(str);
    int w = 0;
    for (int i = 0; i < cnt;)
    {
        if (IsChinese(str + i) == 1)
        {
            i += 2;
            w += FONT_SIZE;
        }
        else
        {
            i++;
            w += FONT_SIZE / 2;
        }
    }

    return w;
}

void LCD_ShowStringV2(uint16_t x, uint16_t y, const char *p, uint16_t fc, uint16_t bc, uint8_t sizey, uint8_t mode)
{
    size_t cnt = strlen(p);
    char tmp[LCD_W] = { 0 };
    char c = 0;
    int offset = 0;
    int pre = -1; // -1: init, 0: chinese, 1: non-chinese
    int i;

    memcpy(tmp, p, cnt);
    for (i = 0; i < cnt;)
    {
        if (IsChinese(tmp + i) == 1)
        {
            if (pre == -1)
                pre = 0;
            else if (pre != 0)
            {
                c = tmp[i];
                tmp[i] = 0;
                LCD_ShowString(x, y, (const uint8_t*)(tmp+offset), fc, bc, sizey, mode);
                // switch show
                tmp[i] = c;
                x += sizey * (i - offset) / 2; 
                pre = 0;
                offset = i;
            }
            i += 2;
        }
        else
        {
            if (pre == -1)
                pre = 1;
            else if (pre != 1)
            {
                c = tmp[i];
                tmp[i] = 0xFF;
                LCD_ShowChinese(x, y, (const uint8_t*)(tmp+offset), fc, bc, sizey, mode);
                // switch show
                tmp[i] = c;
                x += sizey * (i - offset) / 2; 
                pre = 1;
                offset = i;
            }
            i += 1;
        }
    }

    if (pre == 0)
        LCD_ShowChinese(x, y, (const uint8_t*)(tmp+offset), fc, bc, sizey, mode);
    else if (pre == 1)
        LCD_ShowString(x, y, (const uint8_t*)(tmp+offset), fc, bc, sizey, mode);
}

static int lastX = 0;
static int lastY = 0;

void ResetCurveState()
{
    lastX = 0;
    lastY = 0;
}

int NormalizeY(int value, int maxV)
{
    float val = (float)value / (float)maxV;
    return (int)(val * CURVE_HEIGHT * MAX_VALUE_RATIO);
}

void DrawBoundingBox(int sx, int sy, int width, int height, uint16_t color)
{
    int x1 = sx - BOUND_GAPX;
    int y1 = sy - BOUND_GAPY;
    int x2 = sx + width + BOUND_GAPX;
    int y2 = sy + height + BOUND_GAPY;
    LCD_DrawLine(x1, y1, x2, y1, color);
    LCD_DrawLine(x1, y2, x2, y2, color);
    LCD_DrawLine(x1, y1, x1, y2, color);
    LCD_DrawLine(x2, y1, x2, y2, color);
}

void DrawZeroMark(int sx, int sy, int width, int height, uint16_t color)
{
    LCD_DrawLine(sx, sy + height / 2, sx - ZERO_MARK_WIDTH, sy + height / 2, color);
    LCD_DrawLine(sx + width, sy + height / 2, sx + width + ZERO_MARK_WIDTH, sy + height / 2, color);
}

void ClearCurve(int sx, int sy, int width, int height, uint16_t color)
{
    DrawBoundingBox(sx, sy, width, height, color);
    DrawZeroMark(sx, sy, width, height, color);
    LCD_Fill(sx, sy, sx + width + BOUND_GAPX, sy + height + BOUND_GAPY, color);
}

int DrawCurve(int sx, int sy, int width, int height, uint16_t color, uint16_t bgColor, int curveValue)
{
    int y = sy + height - curveValue;

    int x = lastX + 1; // 更新 X 坐标(时间轴)
    int maxX = sx + width;
    int maxY = sy + height;

    if (x < maxX)
    {
        if (lastY == 0) // first point
        {
            LCD_DrawPoint(sx, y, color);
            lastX = sx;
            lastY = y;
        }
        else
        {
            LCD_DrawLine(x, sy, x, maxY, bgColor);       // clear point of preview draw
            LCD_DrawLine(lastX, lastY, x, y, color);            // line from previous point to current point
            LCD_DrawLine(x + 1, sy, x + 1, maxY, WHITE); // draw indicator line of next update point
            lastX = x;
            lastY = y;
        }
    }
    else
    {
        // draw from start
        LCD_DrawLine(maxX, sy, maxX, maxY, bgColor);
        LCD_DrawLine(sx, sy, sx, maxY, bgColor);
        LCD_DrawPoint(sx, y, color);
        lastX = sx;
        lastY = y;
    }

    return lastX;
}
